/*
 * Copyright (C) 2020 The zfoo Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and limitations under the License.
 */

package org.ricks.ioc.scheduler;

import org.ricks.ioc.BeanAnalysisProcessor;
import org.ricks.ioc.HotfixManager;
import org.ricks.ioc.utils.*;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * 这是一个后置处理器，在boot项目中注册EventContext时，会import导入EventRegisterProcessor这个组件，这是一个后置处理器，
 * 断点发现 在AbstractAutowireCapableBeanFactory或调用getBeanPostProcessors，这样子每一个Bean创建后都会走postProcessAfterInitialization这个方法
 *
 */
public class SchedulerRegisterProcessor implements BeanAnalysisProcessor {

    @Override
    public Object postProcessAfterInitialization(Object bean) throws IocException {
        // 优先使用热更后的类
        Class<?> actualClass = HotfixManager.getHotfixClass(bean.getClass().getName());
        if (actualClass != null) {
            try {
                // 取消旧bean的调度任务
                cancelScheduledTasks(bean);
                // 创建热更后的实例并复制字段值
                Object hotfixBean = actualClass.newInstance();
                copyFieldValues(bean, hotfixBean);
                bean = hotfixBean;

            } catch (Exception e) {
                Logger.error("创建热更Scheduler实例失败", e);
                return bean; // 如果热更失败，返回原始bean
            }
        }

        var clazz = bean.getClass();
        var methods = ReflectUtils.getMethodsByAnnoInPOJOClass(clazz, Scheduled.class);
        if (ArrayUtils.isEmpty(methods)) {
            return bean;
        }

        if (!ReflectUtils.isPojoClass(clazz)) {
            Logger.warn(StringUtils.format("The message registration class [{}] is not a POJO class, and the parent class " +
                    "will not be " +
                    "scanned", clazz));
        }

        try {
            for (var method : methods) {
                registerScheduledMethod(bean, method);
            }
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }

        return bean;
    }

    /**
     * 注册调度方法
     */
    private void registerScheduledMethod(Object bean, Method method) throws Throwable {
        var schedulerMethod = method.getAnnotation(Scheduled.class);

        var paramClazzs = method.getParameterTypes();
        if (paramClazzs.length >= 1) {
            throw new IllegalArgumentException(StringUtils.format("[class:{}] [method:{}] can not have any parameters",
                    bean.getClass(), method.getName()));
        }

        var methodName = method.getName();

        if (!Modifier.isPublic(method.getModifiers())) {
            throw new IllegalArgumentException(StringUtils.format("[class:{}] [method:{}] must use 'public' as modifier!",
                    bean.getClass().getName(), methodName));
        }

        if (Modifier.isStatic(method.getModifiers())) {
            throw new IllegalArgumentException(StringUtils.format("[class:{}] [method:{}] can not use 'static' as modifier!",
                    bean.getClass().getName(), methodName));
        }

        // 关键修改：检查是否应该使用增强方式
        boolean useEnhancement = Runtime.version().feature() >= 24 &&
                !HotfixManager.isHotfixClass(bean.getClass());

        // 先生成任务ID
        String taskId = generateTaskId(bean, method);

        // 在注册新任务前，先取消可能存在的旧任务（安全措施）
        SchedulerBus.cancelTask(taskId);

//        if (!StringUtils.isBlank(schedulerMethod.cron())) {
//            var scheduler = SchedulerDefinition.valueOf(schedulerMethod.cron(), bean, method);
//            SchedulerBus.registerTask(scheduler);
//        }
//
//        if (schedulerMethod.initialDelay() >= 0 && schedulerMethod.fixedRate() > 0) {
//            var scheduler = SchedulerDefinition.valueOf(schedulerMethod.initialDelay(), schedulerMethod.fixedRate(), bean, method);
//            SchedulerBus.registerTask(scheduler);
//        }
        if (!StringUtils.isBlank(schedulerMethod.cron())) {
            var scheduler = SchedulerDefinition.valueOf(schedulerMethod.cron(), bean, method);
            // 确保使用统一的任务ID
            scheduler.setTaskId(taskId);
            SchedulerBus.registerTask(scheduler);
        }

        if (schedulerMethod.initialDelay() >= 0 && schedulerMethod.fixedRate() > 0) {
            var scheduler = SchedulerDefinition.valueOf(schedulerMethod.initialDelay(), schedulerMethod.fixedRate(), bean, method);
            // 确保使用统一的任务ID
            scheduler.setTaskId(taskId);
            SchedulerBus.registerTask(scheduler);
        }

        // 添加延迟任务的注册
        if (schedulerMethod.initialDelay() >= 0 && schedulerMethod.fixedRate() <= 0) {
            var scheduler = SchedulerDefinition.valueOf(schedulerMethod.initialDelay(), bean, method);
            // 确保使用统一的任务ID
            scheduler.setTaskId(taskId);
            SchedulerBus.registerTask(scheduler);
        }
    }

    /**
     * 取消已注册的调度任务（修复版本）
     */
    public void cancelScheduledTasks(Object bean) {
        try {
            // 获取bean的所有方法
            Method[] methods = bean.getClass().getMethods();
            for (Method method : methods) {
                if (method.isAnnotationPresent(Scheduled.class)) {
                    // 使用与注册时相同的规则生成任务标识符
                    String taskId = generateTaskId(bean, method);
                    // 取消任务
                    boolean cancelled = SchedulerBus.cancelTask(taskId);
                    if (cancelled) {
                        Logger.debug("成功取消任务: " + taskId);
                    } else {
                        Logger.debug("任务不存在或已被取消: " + taskId);
                    }
                }
            }

            // 额外安全措施：通过类名再次清理（双重保障）
            SchedulerBus.cancelTasksForClass(bean.getClass());
        } catch (Exception e) {
            Logger.warn("取消调度任务失败", e);
        }
    }

    /**
     * 生成任务标识符（与SchedulerDefinition中保持一致）
     */
    private String generateTaskId(Object bean, Method method) {
        return bean.getClass().getName() + "#" + method.getName();
    }



    /**
     * 复制字段值从旧实例到新实例
     */
    public void copyFieldValues(Object source, Object target) {
        Class<?> sourceClass = source.getClass();
        Class<?> targetClass = target.getClass();

        while (sourceClass != null && targetClass != null) {
            for (Field sourceField : sourceClass.getDeclaredFields()) {
                try {
                    Field targetField = targetClass.getDeclaredField(sourceField.getName());
                    if (targetField.getType().isAssignableFrom(sourceField.getType())) {
                        sourceField.setAccessible(true);
                        targetField.setAccessible(true);

                        // 复制字段值
                        Object value = sourceField.get(source);
                        targetField.set(target, value);
                    }
                } catch (NoSuchFieldException | IllegalAccessException e) {
                    // 忽略不存在的字段或访问异常
                }
            }
            sourceClass = sourceClass.getSuperclass();
            targetClass = targetClass.getSuperclass();
        }
    }
}